package fr.cephb.locustree;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Enumeration;
import java.util.Iterator;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.XMLConstants;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.Name;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPMessage;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;

import org.w3c.dom.Element;

import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.Transaction;

import fr.cephb.berkeleydb.db.Walker;
import fr.cephb.json.JSONBuilder;
import fr.cephb.util.Cast;
import fr.cephb.xml.SOAP;
import fr.cephb.xml.WSDL;
import fr.cephb.xml.XML;
import fr.cephb.xml.XSD;
import fr.cephb.xml.XSI;

/**
 * SoapServlet
 * @author pierre
 *
 */
public class SoapServlet
	extends HttpServlet
	{
	private static final long serialVersionUID = 1L;
	private MessageFactory messageFactory;
	@Override
	public void init() throws ServletException
		{
		try
			{
			this.messageFactory = MessageFactory.newInstance();
			}
		catch (Exception e)
			{
			throw new ServletException(e);
			}
		}
	@Override
	protected void service(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException
		{
		LTModel model= LTModel.class.cast(req.getAttribute("model"));
		if(model==null) throw new ServletException("model is null");
		ServletOutputStream out=res.getOutputStream();
		XMLOutputFactory xmlfactory= XMLOutputFactory.newInstance();
		try
			{
			res.setContentType("text/xml");
			XMLStreamWriter w = xmlfactory.createXMLStreamWriter(out, "UTF-8");
			w.writeStartDocument("UTF-8", "1.0");
			if(req.getParameter("wsdl")!=null)
				{
				printWsdl(w,req,res);
				}
			else if(req.getContentType()!=null &&
					req.getMethod().equalsIgnoreCase("POST") && 
					req.getContentType().startsWith("text/xml"))
				{
				processSoapQuery(w,req,res);
				}
			else
				{
				w.writeEmptyElement("error");
				}
			w.writeEndDocument();
			w.flush();
			w.close();
			}
		catch (XMLStreamException err)
			{
			throw new IOException(err);
			}
		}
	
	private String getTargetNamespace()
		{
		return "http://webservices.cephb.fr/locustree/";
		}
	
	
	private void message(XMLStreamWriter w,String messageName,String paramName)
		throws XMLStreamException
		{
		w.writeStartElement("message");
        w.writeAttribute("name",messageName);
        w.writeEmptyElement("part");
        w.writeAttribute("name","parameters");
        w.writeAttribute("element",paramName);
        w.writeEndElement();//message
		}
	
	
	private void operation(XMLStreamWriter w,String name,String input,String output)
	throws XMLStreamException
		{
        /* operation : getOrganisms */
        w.writeStartElement("operation");
        w.writeAttribute("name",name);
        w.writeEmptyElement("input");
        w.writeAttribute("message",input);
        w.writeEmptyElement("output");
        w.writeAttribute("message",output);
        w.writeEndElement();//operation
		}
	
	private void printWsdl(XMLStreamWriter w,
		HttpServletRequest req,
		HttpServletResponse res
		)
		throws XMLStreamException
		{
        w.writeStartElement("definitions");
        
        
        //xmlns
        w.writeAttribute("xmlns",WSDL.NS);
        w.writeAttribute(XMLConstants.XMLNS_ATTRIBUTE,XMLConstants.XML_NS_URI,"xsd",XSD.NS);
        w.writeAttribute(XMLConstants.XMLNS_ATTRIBUTE,XMLConstants.XML_NS_URI,"soap",SOAP.NS);
        w.writeAttribute(XMLConstants.XMLNS_ATTRIBUTE,XMLConstants.XML_NS_URI,"tns",getTargetNamespace());
        w.writeAttribute("targetNamespace",getTargetNamespace());
        w.writeAttribute("name","LocusTreeService");
        
        final String context=
        	req.getScheme()+"://"+
        	req.getLocalName()+":"+req.getLocalPort()+
        	"/"+req.getContextPath()
        	;
        /*
        w.writeComment("pi "+context);
        w.writeComment("pi "+req.getPathInfo());
        w.writeComment("pt "+req.getPathTranslated());
        w.writeComment("sp "+req.getServletPath());
        w.writeComment("ru "+req.getRequestURL());
        w.writeComment("la "+req.getLocalAddr());
        w.writeComment("ln "+req.getLocalName());
        w.writeComment("ru "+req.getRequestURI());
        w.writeComment("ru "+req.getScheme());
        w.writeComment("ru "+req.getServerName());
        w.writeComment("pr "+req.getProtocol());*/
        //types
        w.writeStartElement("types");
        w.writeStartElement("xsd","schema",XSD.NS);
        w.writeEmptyElement("xsd","import",XSD.NS);
        w.writeAttribute("namespace",getTargetNamespace());
        w.writeAttribute("schemaLocation",context+"/static/ws/schema.xsd");
        
       
        w.writeEndElement();//xsd:schema
        w.writeEndElement();//types
        
        
        //=======================================
        
       
        message(w,"getOrganisms","tns:getOrganisms");
        message(w,"GetOrganismsResponse","tns:Organisms");
        message(w,"getChromosomes","tns:getChromosomes");
        message(w,"GetChromosomesResponse","tns:Chromosomes");
        message(w,"getTracks","tns:getTracks");
        message(w,"GetTracksResponse","tns:Tracks");
        message(w,"getEntities","tns:getEntities");
        message(w,"GetEntitiesResponse","tns:Entities");
        
        /* portType */
        w.writeStartElement("portType");
        w.writeAttribute("name","LocusTree");

        
        operation(w,"getOrganisms", "tns:getOrganisms", "tns:GetOrganismsResponse");
        operation(w,"getChromosomes", "tns:getChromosomes", "tns:GetChromosomesResponse");
        operation(w,"getTracks", "tns:getTracks", "tns:GetTracksResponse");
        operation(w,"getEntities", "tns:getEntities", "tns:GetEntitiesResponse");
        
        
       w.writeEndElement();//portType
                         
       w.writeStartElement("binding");

        w.writeAttribute("name","LocusTreePortBinding");

        w.writeAttribute("type","tns:LocusTree");
        w.writeEmptyElement("soap","binding",SOAP.NS);
        w.writeAttribute("transport",SOAP.HTTP);
        w.writeAttribute("style","document");
        
        for(String opName:new String[]{
        		"getOrganisms","getChromosomes",
        		"getTracks","getEntities"})
        	{
	        w.writeStartElement("operation");
	        w.writeAttribute("name",opName);
	        w.writeEmptyElement("soap","operation",SOAP.NS);
	        w.writeAttribute("soapAction","");
	        for(int side=0;side<2;++side)
	        	{
		        w.writeStartElement(side==0?"input":"output");
		        w.writeEmptyElement("soap","body",SOAP.NS);
		        w.writeAttribute("use","literal");
		        w.writeEndElement();
	        	}
	        
	        w.writeEndElement();//operation
        	}
         
        w.writeEndElement();//binding
        
        /* service */
        w.writeStartElement("service");
        w.writeAttribute("name","LocusTreeService");
        
        w.writeStartElement("port");

        w.writeAttribute("name","LocusTreePort");
        w.writeAttribute("binding","tns:LocusTreePortBinding");
        w.writeStartElement("soap","address",SOAP.NS);
        w.writeAttribute("location",context+"/locustree/soap");
        w.writeEndElement();//soap
        w.writeEndElement();//port
        w.writeEndElement();//service
        w.writeEndElement();//definitions
		}
	
	public MessageFactory getMessageFactory()
		{
		return messageFactory;
		}
	private Transaction getTransaction()
		{
		return null;
		}

	private void processSoapQuery(XMLStreamWriter w,
			HttpServletRequest req,
			HttpServletResponse res
			)
		throws XMLStreamException
		{
		MimeHeaders headers=new MimeHeaders();
		Enumeration<?> e=req.getHeaderNames();
		while(e.hasMoreElements())
			{
			String h=(String)e.nextElement();
			Enumeration<?> v=req.getHeaders(h);
			while(v.hasMoreElements())
				{
				headers.addHeader(h, (String)v.nextElement());
				}
			}
		
		try
			{
			
			SOAPMessage message=getMessageFactory().createMessage(headers,req.getInputStream());
			SOAPBody body=message.getSOAPBody();
			Iterator<?> iter=body.getChildElements();
			while(iter.hasNext())
				{
				Object next_e=iter.next();
				if(next_e==null || !(next_e instanceof SOAPElement)) continue;
				SOAPElement child =SOAPElement.class.cast(next_e);
				Name name= child.getElementName();
				if(!name.getURI().equals(child.getNamespaceURI())) continue;
				if(name.getLocalName().equals("getOrganisms"))
					{
					processGetOrganisms(w,message,req,res);
					return;
					}
				else if(name.getLocalName().equals("getChromosomes"))
					{
					processGetChromosomes(w,message,child,req,res);
					return;
					}
				else if(name.getLocalName().equals("getEntities"))
					{
					processGetEntities(w,message,child,req,res);
					return;
					}
				else if(name.getLocalName().equals("getTracks"))
					{
					processGetTracks(w,message,req,res);
					return;
					}
				}
			}
		catch (Exception err)
			{
			SOAPError(w,req,res,err,err.getMessage());
			return;
			}
		SOAPError(w,req,res,null,"No Processed");
		}

	private void processGetOrganisms(
			XMLStreamWriter w,
			SOAPMessage message,
			HttpServletRequest req,
			HttpServletResponse res
			) throws XMLStreamException
	{
	LTModel model=LTModel.class.cast(req.getAttribute("model"));
	
	Walker<Integer,Organism> i=null;
	try
		{
		final String pfx="ceph";
		i= model.getOrganismDB().openWalker(getTransaction());
		
		w.writeStartElement("Envelope");
	    w.writeAttribute("xmlns",SOAP.ENVELOPE);
	    w.writeAttribute(XMLConstants.XMLNS_ATTRIBUTE,XMLConstants.XML_NS_URI,"xsd",XSD.NS);
	    w.writeAttribute(XMLConstants.XMLNS_ATTRIBUTE,XMLConstants.XML_NS_URI,"xsi",XSI.NS);
	    w.writeStartElement("Body");
		
		w.writeStartElement(pfx, "Organisms", getTargetNamespace());
		w.writeAttribute(XMLConstants.XMLNS_ATTRIBUTE,XMLConstants.XML_NS_URI,pfx,getTargetNamespace());
		
		while(i.next())
			{
			Organism org=i.getValue();
			
		
			w.writeStartElement(pfx, "Organism", getTargetNamespace());
			
			w.writeStartElement(pfx, "id", getTargetNamespace());
			w.writeCharacters(String.valueOf(org.getId()));
			w.writeEndElement();
			
			w.writeStartElement(pfx, "name", getTargetNamespace());
			w.writeCharacters(org.getName());
			w.writeEndElement();
			
			w.writeStartElement(pfx, "description", getTargetNamespace());
			w.writeCharacters(org.getDescription());
			w.writeEndElement();
			
			w.writeStartElement(pfx, "metadata", getTargetNamespace());
			w.writeCharacters(org.getMetadataAsJson());
			w.writeEndElement();
			
			w.writeEndElement();
				
			}
		w.writeEndElement();//organisms
		w.writeEndElement();//Body
	    w.writeEndElement();//ENv
		}
	catch (Exception err)
		{
		SOAPError(w,req,res,err,null);
		}
	finally
		{
		if(i!=null) i.close();
		}
	
	}
	
	
	private void processGetTracks(
			XMLStreamWriter w,
			SOAPMessage message,
			HttpServletRequest req,
			HttpServletResponse res
			) throws XMLStreamException
	{
	LTModel model=LTModel.class.cast(req.getAttribute("model"));
	
	Walker<Integer,Track> i=null;
	try
		{
		final String pfx="ceph";
		i= model.getTracksDB().openWalker(getTransaction());
		
		w.writeStartElement("Envelope");
	    w.writeAttribute("xmlns",SOAP.ENVELOPE);
	    w.writeAttribute(XMLConstants.XMLNS_ATTRIBUTE,XMLConstants.XML_NS_URI,"xsd",XSD.NS);
	    w.writeAttribute(XMLConstants.XMLNS_ATTRIBUTE,XMLConstants.XML_NS_URI,"xsi",XSI.NS);
	    w.writeStartElement("Body");
		
		w.writeStartElement(pfx, "Tracks", getTargetNamespace());
		w.writeAttribute(XMLConstants.XMLNS_ATTRIBUTE,XMLConstants.XML_NS_URI,pfx,getTargetNamespace());
		
		while(i.next())
			{
			Track track=i.getValue();
			
		
			w.writeStartElement(pfx, "Track", getTargetNamespace());
			
			w.writeStartElement(pfx, "id", getTargetNamespace());
			w.writeCharacters(String.valueOf(track.getId()));
			w.writeEndElement();
			
			w.writeStartElement(pfx, "name", getTargetNamespace());
			w.writeCharacters(track.getName());
			w.writeEndElement();
			
			w.writeStartElement(pfx, "description", getTargetNamespace());
			w.writeCharacters(track.getDescription());
			w.writeEndElement();
			
			w.writeStartElement(pfx, "metadata", getTargetNamespace());
			w.writeCharacters(track.getMetadataAsJson());
			w.writeEndElement();
			
			w.writeEndElement();
				
			}
		w.writeEndElement();//organisms
		w.writeEndElement();//Body
	    w.writeEndElement();//ENv
		}
	catch (Exception err)
		{
		SOAPError(w,req,res,err,null);
		}
	finally
		{
		if(i!=null) i.close();
		}
	
	}
	
	private void processGetChromosomes(
			XMLStreamWriter w,
			SOAPMessage message,
			SOAPElement root,
			HttpServletRequest req,
			HttpServletResponse res
			) throws XMLStreamException
	{
	Element e=XML.oneElement(root,getTargetNamespace(),"organismId");
	String s=e.getTextContent();
	if(!Cast.IntegerGreaterThanZero.isA(s))
		{
		SOAPError(w, req, res, null, "orgnism id is not an integer");
		return;
		}
	Integer organismId=Cast.IntegerGreaterThanZero.cast(s);
	
	LTModel model=LTModel.class.cast(req.getAttribute("model"));
	
	
	try
		{
		final String pfx="ceph";
		
		if(!model.getOrganismDB().containsKey(getTransaction(), organismId))
			{
			SOAPError(w, req, res, null, "undefined orgnism-id:"+organismId);
			return;
			}
		
		
		
		w.writeStartElement("Envelope");
	    w.writeAttribute("xmlns",SOAP.ENVELOPE);
	    w.writeAttribute(XMLConstants.XMLNS_ATTRIBUTE,XMLConstants.XML_NS_URI,"xsd",XSD.NS);
	    w.writeAttribute(XMLConstants.XMLNS_ATTRIBUTE,XMLConstants.XML_NS_URI,"xsi",XSI.NS);
	    w.writeStartElement("Body");
		
		w.writeStartElement(pfx, "Chromosomes", getTargetNamespace());
		w.writeAttribute(XMLConstants.XMLNS_ATTRIBUTE,XMLConstants.XML_NS_URI,pfx,getTargetNamespace());
		
		for(ChromInfo ci:model.getChromsomesByOrganismId(getTransaction(), organismId))
			{
			
			w.writeStartElement(pfx, "Chromosome", getTargetNamespace());
			
			w.writeStartElement(pfx, "id", getTargetNamespace());
			w.writeCharacters(String.valueOf(ci.getId()));
			w.writeEndElement();
			
			w.writeStartElement(pfx, "organismId", getTargetNamespace());
			w.writeCharacters(String.valueOf(ci.getOrganismId()));
			w.writeEndElement();
			
			w.writeStartElement(pfx, "name", getTargetNamespace());
			w.writeCharacters(ci.getName());
			w.writeEndElement();
			
			w.writeStartElement(pfx, "length", getTargetNamespace());
			w.writeCharacters(String.valueOf(ci.getLength()));
			w.writeEndElement();
			
			w.writeStartElement(pfx, "metadata", getTargetNamespace());
			w.writeCharacters(ci.toJSON());
			w.writeEndElement();
			
			w.writeEndElement();
				
			}
		w.writeEndElement();//organisms
		w.writeEndElement();//Body
	    w.writeEndElement();//ENv
		}
	catch (Exception err)
		{
		SOAPError(w,req,res,err,null);
		}
	}
	
	
	private void processGetEntities(
			XMLStreamWriter w,
			SOAPMessage message,
			SOAPElement root,
			HttpServletRequest req,
			HttpServletResponse res
			) throws XMLStreamException
	{
	
	LTModel model=LTModel.class.cast(req.getAttribute("model"));
	
	
	
	Element e=XML.oneElement(root,getTargetNamespace(),"organismId");
	String s=e.getTextContent();
	if(!Cast.IntegerGreaterThanZero.isA(s))
		{
		SOAPError(w, req, res, null, "organism id is not an integer");
		return;
		}
	Integer organismId=Cast.IntegerGreaterThanZero.cast(s);
	Organism organism=model.getOrganismDB().get(getTransaction(), organismId);
	if(organism==null)
		{
		SOAPError(w, req, res, null, "undefined orgnism-id:"+organismId);
		return;
		}
	
	e=XML.oneElement(root,getTargetNamespace(),"chromosomeId");
	s=e.getTextContent();
	if(!Cast.IntegerGreaterThanZero.isA(s))
		{
		SOAPError(w, req, res, null, "chromosome id is not an integer");
		return;
		}
	Integer chromId=Cast.IntegerGreaterThanZero.cast(s);
	ChromInfo chromInfo =model.getChromDB().get(getTransaction(), chromId);
	if(chromInfo==null || !chromInfo.getOrganismId().equals(organism.getId()))
		{
		SOAPError(w, req, res, null, "bad chrom-id:"+chromId);
		return;
		}

	e=XML.oneElement(root,getTargetNamespace(),"trackId");
	s=e.getTextContent();
	if(!Cast.IntegerGreaterThanZero.isA(s))
		{
		SOAPError(w, req, res, null, "track id is not an integer");
		return;
		}
	Integer trackId=Cast.IntegerGreaterThanZero.cast(s);
	Track track= model.getTracksDB().get(getTransaction(), trackId);
	if(track==null)
		{
		SOAPError(w, req, res, null, "bad track-id:"+track);
		return;
		}
	
	e=XML.oneElement(root,getTargetNamespace(),"start");
	s=e.getTextContent();
	if(!Cast.Integer.isA(s))
		{
		SOAPError(w, req, res, null, "start id is not an integer");
		return;
		}
	Integer start=Cast.Integer.cast(s);
	
	e=XML.oneElement(root,getTargetNamespace(),"end");
	s=e.getTextContent();
	if(!Cast.Integer.isA(s))
		{
		SOAPError(w, req, res, null, "end id is not an integer");
		return;
		}
	Integer end=Cast.Integer.cast(s);
	
	
	if(start<0 || start>end)
		{
		SOAPError(w, req, res, null, "bad start/end index");
		return;
		}
	
	e=XML.firstElement(root,getTargetNamespace(),"limit");
	int limit=Integer.MAX_VALUE;
	if(e!=null)
		{
		s=e.getTextContent();
		if(Cast.Integer.isA(s))
			{
			limit=Cast.Integer.cast(s);
			if(limit<0) limit=0;
			}
		}
	
	e=XML.firstElement(root,getTargetNamespace(),"index");
	int index=0;
	if(e!=null)
		{
		s=e.getTextContent();
		if(Cast.Integer.isA(s))
			{
			index=Cast.Integer.cast(s);
			if(index<0) limit=0;
			}
		}

	
	try
		{
		final String pfx="ceph";
		
		Long nodeid= model.getTrackChrom2NodeId().get(
				getTransaction(),
				new TrackChrom(track.getId(),chromInfo.getId()));
		
		
		w.writeStartElement("Envelope");
	    w.writeAttribute("xmlns",SOAP.ENVELOPE);
	    w.writeAttribute(XMLConstants.XMLNS_ATTRIBUTE,XMLConstants.XML_NS_URI,"xsd",XSD.NS);
	    w.writeAttribute(XMLConstants.XMLNS_ATTRIBUTE,XMLConstants.XML_NS_URI,"xsi",XSI.NS);
	    w.writeStartElement("Body");
		
		w.writeStartElement(pfx, "Entities", getTargetNamespace());
		w.writeAttribute(XMLConstants.XMLNS_ATTRIBUTE,XMLConstants.XML_NS_URI,pfx,getTargetNamespace());
		//recursive call
		if(nodeid!=null)
			{
			processEntities(w, pfx, model, nodeid, organism, track, chromInfo, start, end);
			}
		
		w.writeEndElement();//entities
		w.writeEndElement();//Body
	    w.writeEndElement();//ENv
		}
	catch (Exception err)
		{
		SOAPError(w,req,res,err,null);
		}
	}
	
	
	private void processEntities(
			XMLStreamWriter w,
			String pfx,
			LTModel model,
			long nodeid,
			Organism organism,
			Track track,
			ChromInfo ci,
			int start,
			int end) throws XMLStreamException,ServletException,DatabaseException,IOException
		{
		if(nodeid==LTNode.NIL) return;
		LTNode node= model.getLocusNodeDB().get(getTransaction(), nodeid);
		if(node==null) return;//?
		if(node.getStart()>= end) return;
		if(node.getEnd()<= start) return;
		if(node.hasEntities())
			{
			for(MappedObject o:node.getEntities())
				{
				if(o.getStart()>= end) return;
				if(o.getEnd()<= start) return;
				w.writeStartElement(pfx, "Entity", getTargetNamespace());
	
				
				w.writeStartElement(pfx, "organismId", getTargetNamespace());
				w.writeCharacters(String.valueOf(organism.getId()));
				w.writeEndElement();
				
				w.writeStartElement(pfx, "chromosomeId", getTargetNamespace());
				w.writeCharacters(String.valueOf(ci.getId()));
				w.writeEndElement();
				
				w.writeStartElement(pfx, "trackId", getTargetNamespace());
				w.writeCharacters(String.valueOf(track.getId()));
				w.writeEndElement();
				
				w.writeStartElement(pfx, "id", getTargetNamespace());
				w.writeCharacters(o.getId());
				w.writeEndElement();
				
				w.writeStartElement(pfx, "name", getTargetNamespace());
				w.writeCharacters(o.getName());
				w.writeEndElement();				
				
				w.writeStartElement(pfx, "metadata", getTargetNamespace());
				if(o.getJSON()!=null)
					{
					w.writeCharacters(new JSONBuilder().toString(o.getJSON()));
					}
				w.writeEndElement();
				
				
				w.writeStartElement(pfx, "start", getTargetNamespace());
				w.writeCharacters(String.valueOf(o.getStart()));
				w.writeEndElement();
				
				w.writeStartElement(pfx, "end", getTargetNamespace());
				w.writeCharacters(String.valueOf(o.getEnd()));
				w.writeEndElement();
				
				
				w.writeEndElement();
				}
			}
		if(node.hasSubNodes())
			{
			for(Long sub: node.getSubNodesId())
				{
				processEntities(w,pfx,model,sub,organism,track,ci,start,end);
				}
			}
		}
	
	
	
	private void SOAPError(XMLStreamWriter w,
			HttpServletRequest req,
			HttpServletResponse res,
			Throwable err,
			String message
			) throws XMLStreamException
		{
		
		if(err!=null && message==null) message=err.getMessage();
		if(message==null) message="Error";
		//res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
		w.writeStartElement("Envelope");
        w.writeAttribute("xmlns",SOAP.ENVELOPE);
        w.writeAttribute(XMLConstants.XMLNS_ATTRIBUTE,XMLConstants.XML_NS_URI,"xsd",XSD.NS);
        w.writeAttribute(XMLConstants.XMLNS_ATTRIBUTE,XMLConstants.XML_NS_URI,"xsi",XSI.NS);
		w.writeStartElement("Body");
		w.writeStartElement("Fault");
		
		w.writeStartElement("faultcode");
		w.writeAttribute("xsi",XSI.NS,"type","string");
		w.writeCharacters(message);
		w.writeEndElement();
		
		w.writeStartElement("faultstring");
		w.writeAttribute("xsi",XSI.NS,"type","string");
		if(err!=null)
			{
			StringWriter sw=new StringWriter();
			PrintWriter pw=new PrintWriter(sw);
			err.printStackTrace(pw);
			pw.flush();
			w.writeCharacters(sw.toString());
			}
		else
			{
			w.writeCharacters(message);
			}
		w.writeEndElement();
		

		w.writeEndElement();//Fault
		w.writeEndElement();//Body
        w.writeEndElement();//ENv
		}
	
	}
